package com.gitee.beiding.template_excel;


import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;


/*

    根据变量名称构建H对象,H对象维护数据的上下级关系

    例如
        a.list[i].d

        H(a)->H(list[i])->H(d)

    H对象在处理的过程中,会先给叶子节点赋值,然后从叶子

 */
class ValueHandler {

//    private Map<String, Class<?>> entityMapping;

    //属性的setter方法
//    private Map<String, Method> setterMap = new HashMap<>();


/*
    void setEntityMapping(Map<String, Class<?>> entityMapping) {
        this.entityMapping = new HashMap<>();

        Set<String> names = new HashSet<>();

        //首先将当前元素放入
        entityMapping.forEach((k, c) -> {
            String name = k.replaceAll("(?<=\\[)[^\\[\\]]*(?=])", "").replaceAll("[\n \t]*", "");
            this.entityMapping.put(name, c);
            names.add(name);
        });


        for (String name : names) {
            putAndHandleFiledType(name, this.entityMapping.get(name));
        }

    }
*/


    /**
     * 预处理类型映射
     * 处理后生成与行号无关的表达式
     * 例如
     * teacher[i] 映射 Teacher类型
     * 处理后
     * teacher[] 映射Teacher类型
     * <p>
     * 预处理,以便深度序列化
     * <p>
     * todo 支持注解,支持使用注解自定义数据类型转换
     */
//    private void putAndHandleFiledType(String name, Class<?> type) {
//
//        Class<?> c = this.entityMapping.get(name);
//
//        //如果类型已经存在就使用已经存在的类型作为解析依据
//        if (c == null) {
//            this.entityMapping.put(name, type);
//        } else {
//            type = c;
//        }
//
//
//        Map<String, Method> map = setterMethodMap(type);
//
//        //解析类中的所有变量
//        for (Field field : fields(type)) {
//            String fn = field.getName();
//
//            //计算setter方法
//            String setterMethodName = setterName(fn);
//
//            try {
//
//
//                Method method = map.get(setterMethodName);
//
//                if (method != null) {
//
//                    //如果是列表只能是List
//                    if (field.getType() == List.class) {
//                        Type genericType = field.getGenericType();
//
//                        //判断是否是具有参数的
//                        if (genericType instanceof ParameterizedType) {
//                            Type[] types = ((ParameterizedType) genericType).getActualTypeArguments();
//                            if (types.length == 1) {
//                                Type t = types[0];
//                                String typeName = t.getTypeName();
//                                Class<?> aClass = Class.forName(typeName);
//                                String subN = name + "." + fn + "[]";
//
//                                //放入setter方法
//                                setterMap.put(subN, method);
//                                putAndHandleFiledType(subN, aClass);
//                            }
//                        }
//
//                    } else {
//                        String subN = name + "." + fn;
//                        setterMap.put(subN, method);
//                        putAndHandleFiledType(subN, field.getType());
//                    }
//                }
//            } catch (Exception ignore) {
//            }
//        }
//
//    }
//
    private static Map<String, Method> setterMethodMap(Class<?> clazz) {
        Map<String, Method> map = new HashMap<>();
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (method.getName().startsWith("set")) {
                map.put(method.getName(), method);
            }
        }
        return map;
    }

    private static String setterName(String s) {
        String setterMethodName = "set" + s.substring(0, 1).toUpperCase();
        if (s.length() > 1) {
            setterMethodName += s.substring(1);
        }
        return setterMethodName;
    }

    private static List<Field> fields(Class<?> cls) {
        List<Field> list = new ArrayList<>();
        while (cls != null && cls != Object.class) {
            Field[] fields = cls.getDeclaredFields();
            list.addAll(Arrays.asList(fields));
            cls = cls.getSuperclass();
        }
        return list;
    }


    /**
     * 值处理器
     * 将字符串类型的数值处理成目标类型
     */
    private interface ValueHandle {
        /**
         * 解析字符串为目标类型
         *
         * @param t
         * @return
         */
        Object handle(String t);
    }

    /**
     * 内置的默认类型处理器
     */
    private static Map<Class, ValueHandle> defaultHandleMap = new HashMap<>();

    /**
     * 当前类型映射
     */
    private Map<Class, ValueHandle> handleMap = new HashMap<>();


    {
        handleMap.putAll(defaultHandleMap);

        //默认的日期解析格式

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        handleMap.put(Date.class, text -> {
            try {
                return simpleDateFormat.parse(text);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });

        handleMap.put(Calendar.class, text -> {
            try {
                Calendar instance = Calendar.getInstance();
                instance.setTime(simpleDateFormat.parse(text));
                return instance;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    static {

        defaultHandleMap.put(Integer.class, text -> Double.valueOf(text).intValue());
        defaultHandleMap.put(int.class, text -> Double.valueOf(text).intValue());
        defaultHandleMap.put(Character.class, text -> Character.highSurrogate(Double.valueOf(text).intValue()));
        defaultHandleMap.put(char.class, text -> Character.highSurrogate(Double.valueOf(text).intValue()));
        defaultHandleMap.put(Long.class, text -> Double.valueOf(text).longValue());
        defaultHandleMap.put(long.class, text -> Double.valueOf(text).longValue());
        defaultHandleMap.put(Double.class, text -> Double.valueOf(text));
        defaultHandleMap.put(double.class, text -> Double.valueOf(text));
        defaultHandleMap.put(Float.class, text -> Double.valueOf(text).floatValue());
        defaultHandleMap.put(float.class, text -> Double.valueOf(text).floatValue());
        defaultHandleMap.put(Boolean.class, text -> Boolean.valueOf(text));
        defaultHandleMap.put(boolean.class, text -> Boolean.valueOf(text));
        defaultHandleMap.put(Short.class, text -> Double.valueOf(text).shortValue());
        defaultHandleMap.put(short.class, text -> Double.valueOf(text).shortValue());

    }

    //需要将数据处理为一个map
    JSONObject handle(Map<String, List<ValueHolder>> map) {


        //根节点
        Root root = new Root();

        List<H> leafs = new ArrayList<>();

        /*
            从叶子节点开始反向倒推数据
         */
        map.forEach((k, v) -> {

            H l = root;

            String[] split = k.split("\\.");


            //处理每个节点的表达式
            for (String s : split) {
                l = l.getSub(s);
            }


            l.valueHolders = v;

//            Class<?> aClass = entityMapping.get(l.mappingTypeExp);
//
//            if (aClass != null) {
//
//                //找到类型处理器
//                ValueHandle handle = handleMap.get(aClass);
//                if (handle != null) {
//                    v.forEach(d -> {
//                        Object value = d.getValue();
//                        if (value != null) {
//                            String text = (String) value;
//                            d.setValue(handle.handle(text));
//                        }
//                    });
//                }
//            }


            leafs.add(l);

        });

        //遍历所有叶子节点,进行反向传递
        for (H leaf : leafs) {
            leaf.transmit();
        }

        return root.r;
    }

    private class Root extends H {

        private JSONObject r = new JSONObject();

        @Override
        void transmit() {
            for (H value : subs.values()) {
                int sum = 0;
                for (ValueHolder holder : value.valueHolders) {
                    sum += holder.getRowSpan();
                }
                value.forward(r, sum);
            }
        }
    }

    private class H {

        private String name;

        void setName(String name) {
            this.name = name;
        }

        private String exp;

        //变化的自变量,如果存在表明是一个数组元素
        private String independent;

        //父级节点
        private H parent;

        //模板中变量数通常不多
        Map<String, H> subs;

        //值占位符
        private List<ValueHolder> valueHolders;

        H getSub(String exp) {
            if (subs == null) {
                subs = new HashMap<>();
            }

            return subs.computeIfAbsent(exp, k -> {
                H h = new H();
                StringUtils.SubStringResult string = StringUtils.pairingSubString(exp, 0, '[', ']');
                if (string == null) {
                    h.setName(exp);
                    h.exp = exp;
                } else {
                    String name = exp.substring(0, string.getStart());
                    String ind = exp.substring(string.getStart() + 1, string.getEnd() - 1);
                    h.setName(name);

                    //TODO 将数组中的自变量擦除
                    h.exp = exp;
                    h.independent = ind;
                }
                h.parent = H.this;
                return h;
            });
        }

        //下一轮的开始索引位置
        private int index = 0;

        private List<Object> findValue(int span) {
            int i;
            List<Object> r = new ArrayList<>();
            int sum = 0;
            for (i = index; i < valueHolders.size(); i++) {
                ValueHolder holder = valueHolders.get(i);
                r.add(holder.getValue());
                sum += holder.getRowSpan();
                if (sum == span) {
                    i++;
                    break;
                } else if (sum > span) {
                    //TODO sum只能小于span或者等于
                    throw new RuntimeException("数组元素无法对齐");
                }
            }
            index = i;
            return r;
        }

        private Set<String> subExps;

        //接受后继节点反向调用
        void back(H sub) {
            if (subExps == null) {
                subExps = new HashSet<>(subs.keySet());
            }
            subExps.remove(sub.exp);
            //如果处理完成
            if (subExps.size() == 0) {
                transmit();
            }

        }


        //分析得到对齐
        private List<Integer> handleAlignArray() {


            Map<Integer, Integer> rowSpanMap = new HashMap<>();

            boolean hasNotArray = false;

            boolean hasArray = false;

            int allRow = 0;

            Set<Integer> arrayAllRowSet = new HashSet<>();

            for (H value : subs.values()) {
                //如果不是数组元素
                if (value.independent == null) {
                    hasNotArray = true;
                    for (int i = 0; i < value.valueHolders.size(); i++) {
                        Integer integer = rowSpanMap.get(i);
                        if (integer == null) {
                            int row = value.valueHolders.get(i).getRowSpan();
                            rowSpanMap.put(i, row);
                            allRow += row;
                        } else {
                            if (value.valueHolders.get(i).getRowSpan() != integer) {
                                throw new RuntimeException("数据无法对齐");
                            }
                        }
                    }
                } else {
                    hasArray = true;
                    int all = 0;
                    for (ValueHolder holder : value.valueHolders) {
                        all += holder.getRowSpan();
                    }
                    arrayAllRowSet.add(all);
                }
            }

            if (hasNotArray) {
                if (hasArray) {
                    for (Integer integer : arrayAllRowSet) {
                        if (integer != allRow) {
                            throw new RuntimeException("数据无法对齐");
                        }
                    }
                }

                List<Integer> integers = new ArrayList<>();

                rowSpanMap.forEach((k, v) -> {
                    integers.add(k, v);
                });

                return integers;
            } else {

                if (hasArray) {
                    if (arrayAllRowSet.size() > 1) {
                        throw new RuntimeException("数据无法对齐");
                    } else {
                        if (arrayAllRowSet.size() == 0) {
                            return Collections.emptyList();
                        } else {
                            for (Integer integer : arrayAllRowSet) {
                                return Collections.singletonList(integer);
                            }
                        }
                    }
                } else {
                    return Collections.emptyList();
                }

            }

            throw new RuntimeException("不可预料的位置");

        }


        //整合所有直接子节点,创建自己的节点
        private void handleValueHolder() {//这里的判断是不正确的

            List<Integer> list = handleAlignArray();

            valueHolders = new LinkedList<>();

            for (Integer row : list) {
                valueHolders.add(new ValueHolder(new HashMap<String, Object>(), row));
            }

//
//            Class<?> aClass = entityMapping.get(mappingTypeExp);
//
//            if (aClass == null) {
//
//            } else {
//                for (Integer row : list) {
//                    try {
//                        Object o = aClass.newInstance();
//                        valueHolders.add(new ValueHolder(o, row));
//                    } catch (Exception e) {
//                        throw new RuntimeException(e);
//                    }
//                }
//            }

/*
            //放入所有子元素
            Map<H, Integer> sumRowMap = new HashMap<>();
            Map<H, Integer> indexMap = new HashMap<>();

            for (H h : subs.values()) {
                sumRowMap.put(h, 0);
                indexMap.put(h, 0);
            }


            while (true) {

                int maxSum = 0;

                //该元素占用的单元格长度
                int row = 0;

                boolean flag = false;

                //找一个索引
                for (H h : subs.values()) {

                    //找到它对应的索引
                    Integer index = indexMap.get(h);

                    //获取跨越的行数
                    ValueHolder holder = h.valueHolders.get(index);

                    int nextIndex = index + 1;

                    //更新该位置的索引
                    indexMap.put(h, nextIndex);

                    //当前累加的总行数
                    int currentSum = sumRowMap.get(h) + holder.getRow();
                    sumRowMap.put(h, currentSum);

                    if (currentSum > maxSum) {
                        maxSum = currentSum;
                        row = holder.getRow();

                        //表明已经到达某个元素的终点,可以结束了
                        if (nextIndex == h.valueHolders.size()) {
                            flag = true;
                        }
                    }


                }


                for (H h : subs.values()) {
                    Integer sum = sumRowMap.get(h);
                    if (sum < maxSum) {

                        int i = indexMap.get(h);
                        for (; true; i++) {
                            if (i >= h.valueHolders.size()) {
                                throw new RuntimeException("无法对齐元素");
                            }
                            ValueHolder holder = h.valueHolders.get(i);
                            sum += holder.getRow();
                            if (sum == maxSum) {
                                i++;
                                sumRowMap.put(h, maxSum);
                                break;
                            }
                        }
                        indexMap.put(h, i);

                    }
                }


                if (valueHolders == null) {
                    valueHolders = new LinkedList<>();
                }


                //TODO 判断是否具有实体映射,如果有实体映射就放入创建一个实体映射,否则放入一个HashMap

                Class<?> aClass = entityMapping.get(mappingTypeExp);
                if (aClass == null) {
                    valueHolders.add(new ValueHolder(new HashMap<String, Object>(), row));
                } else {
                    try {
                        Object o = aClass.newInstance();
                        valueHolders.add(new ValueHolder(o, row));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }


                //判断是否已经处理到最后了

                if (flag) {

                    //遍历一遍判断所有数据是否全部对齐
                    for (H value : subs.values()) {
                        Integer index = indexMap.get(value);
                        if (index != value.valueHolders.size()) {
                            throw new RuntimeException("数据无法对齐");
                        }
                    }

                    break;
                }

            }*/
        }


        //触发传递
        void transmit() {
            if (subs != null) {
                handleValueHolder();
                //告知自己的正向节点中数组元素,进行必要的合并
                for (ValueHolder holder : valueHolders) {
                    for (H value : subs.values()) {
                        value.forward(holder.getValue(), holder.getRowSpan());
                    }
                }
            }

            if (parent != null) {
                parent.back(this);
            }

        }

        void forward(Object f, int row) {

            if (independent == null) {

                List<Object> list = findValue(row);

                if (list.size() == 1) {
                    Map map = (Map) f;
                    map.put(name, list.get(0));
                }

//
//                if (f instanceof Map) {
//
//                } else {
//                    try {
//                        Object o = list.get(0);
//
//                        Method m = setterMap.get(mappingTypeExp);
//                        if (m == null) {
//                            throw new RuntimeException("未找到setter方法:" + mappingTypeExp);
//                        }
//
//                        //Method method = f.getClass().getMethod(setterMethodName, o.getClass());
//                        m.invoke(f, o);
//                    } catch (Exception e) {
//                        throw new RuntimeException(e);
//                    }
//                }

            } else {
                List<Object> list = findValue(row);

                Map map = (Map) f;
                map.put(name, list);

//
//                if (f instanceof Map) {
//
//                } else {
//                    try {
//                        /*Method method = f.getClass().getMethod(setterMethodName, List.class);
//                        method.invoke(f, list);
//
//                        */
//                        Method m = setterMap.get(mappingTypeExp);
//                        if (m == null) {
//                            throw new RuntimeException("未找到setter方法:" + mappingTypeExp);
//                        }
//                        m.invoke(f, list);
//                    } catch (Exception e) {
//                        throw new RuntimeException(e);
//                    }
//                }
            }

        }


    }

}
